package org.dashboard.server.errorcount;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import org.dashboard.client.widget.errorcount.ErrorCountService;
import org.dashboard.shared.Props;

import java.io.File;
import java.io.FileNotFoundException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class ErrorCountServiceImpl extends RemoteServiceServlet implements ErrorCountService {

    private static List<Map<String, Integer>> errorCountsList = new ArrayList<Map<String, Integer>>();
    private static Date nextScanTime;

    public ErrorCountServiceImpl() {
        nextScanTime = new Date();
//        scanLogs();
    }

    public String getChartUrl(int width, int height) throws IllegalArgumentException {

        // scan logs every day when first request hit in seperate thread
//        new Thread() {
//            @Override
//            public void run() {
                scanLogs();
//            }
//        }.start();

        String barLabels = "";
        int maxCount = 2000;
        String data = "";

        // labels
        for (String date : errorCountsList.get(0).keySet()) {
            barLabels += "|" + date;
        }

        // data
        for (Map<String, Integer> dataMap : errorCountsList) {
            Iterator<String> it = dataMap.keySet().iterator();
            data += "|";
            while (it.hasNext()) {
                data += dataMap.get(it.next());
                if(it.hasNext()) data += ",";
            }
        }
        data = data.substring(1);

        // titles
        String[] titlesArray = Props.instance().getErrorCountConfig()[0];
        String titles = "";
        for (int i = 0; i < titlesArray.length; i++) {
            String title = titlesArray[i];
            titles += title;
            if(i < titlesArray.length-1) {
                titles += "|";
            }
        }

        // make url
        String url = "http://chart.apis.google.com/chart" +
                "?chf=bg,lg,50,F3F5F8,0,E7E8E9,1" +
                "&chxl=0:" + barLabels +
                "&chxr=0,1,5|1,0," + maxCount +
                "&chxs=0,224499,11.5,0,_,224499|1,224499,20,0,t,224499" +
                "&chxt=x,y" +
                "&chbh=25,5,10" +
                "&chs="+width+"x"+height +
                "&cht=bvg" +
                "&chco=224499,3072F3" +
                "&chds=0," + maxCount + ",0," + maxCount +
                "&chd=t:" + data +
                "&chdl="+titles +
                "&chtt=Fejl+i+loggen" +
                "&chts=224499,20";
//        System.out.println(url);
        return url;
    }

    static SimpleDateFormat logfileSDF = new SimpleDateFormat("MM-dd-yyyy");
    static SimpleDateFormat logSDF = new SimpleDateFormat("MMM dd, yyyy hh:mm:ss a z");
    static SimpleDateFormat distByDaySDF = new SimpleDateFormat("dd/MM");

    // scans every day after midnight - if serverside is requested
    private void scanLogs() {
        try {
            Calendar cal = Calendar.getInstance();
            if(cal.getTime().after(nextScanTime) || cal.getTime().equals(nextScanTime)) {
                cal.set(Calendar.HOUR_OF_DAY, 23);
                cal.set(Calendar.MINUTE, 59);
                cal.set(Calendar.SECOND, 59);
                cal.set(Calendar.MILLISECOND, 999);
                nextScanTime = cal.getTime();

                String[] filenames = Props.instance().getErrorCountConfig()[1];
                for (int i = 0; i < filenames.length; i++) {
                    String logfile = filenames[i];
                    Map<String, Integer> distributionMap = new LinkedHashMap<String, Integer>();
                    if(logfile.contains("MM-dd-YYYY")) {
                        Calendar now = Calendar.getInstance();
                        now.add(Calendar.DAY_OF_MONTH, -1);
                        Date beginDate = initDistributionMap(distributionMap);
                        for (int j = 0; j < 5; j++) {
                            try {
                                showDistributionByDay(distributionMap, beginDate, logfile.replace("MM-dd-YYYY", logfileSDF.format(now.getTime())));
                            } catch (FileNotFoundException e) {
                                System.out.println(e);
                            }
                            now.add(Calendar.DAY_OF_MONTH, -1);
                        }
                        errorCountsList.add(distributionMap);
                    } else {
                        Date beginDate = initDistributionMap(distributionMap);
                        try {
                            errorCountsList.add(showDistributionByDay(distributionMap, beginDate, logfile));
                        } catch (FileNotFoundException e) {
                            System.out.println(e);
                        }
                    }
                }
            }
        } catch (ParseException e) {
            System.out.println(e);
        }
    }

    private static Map<String, Integer> showDistributionByDay(Map<String, Integer> distributionMap, Date beginDate, String... logfilepathArray) throws FileNotFoundException, ParseException {
        for (String logfilepath : logfilepathArray) {
            Scanner scanner = new Scanner(new File(logfilepath));

            System.out.println("Scanning "+logfilepath);
            try {
                int linecount = 0;
                while (scanner.hasNextLine()) {
                    String line = scanner.nextLine();
                    linecount++;
                    if (line.contains(" <Error> ")) {
                        java.util.Date date = parseDate(line);
                        if(date.after(beginDate)) {
                            String key = distByDaySDF.format(date);
                            if(distributionMap.get(key) != null) {
                                distributionMap.put(key, distributionMap.get(key) + 1);
                            }
                        }
                    }
                }
                System.out.println("Scanned "+linecount+" lines");
                for (String key : distributionMap.keySet()) {
                    Integer value = distributionMap.get(key);
                    System.out.println(key + "\t" + value);
                }
            }
            finally {
                scanner.close();
            }
        }
        return distributionMap;
    }

    private static Date initDistributionMap(Map<String, Integer> distributionMap) {
        Date beginDate = null;
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_MONTH, -1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        cal.add(Calendar.DAY_OF_MONTH, -4);
        beginDate = cal.getTime();
        distributionMap.put(distByDaySDF.format(cal.getTime()), 0);
        for (int i = 0; i < 4; i++) {
            cal.add(Calendar.DAY_OF_MONTH, 1);
            distributionMap.put(distByDaySDF.format(cal.getTime()), 0);
        }
        return beginDate;
    }

    private static java.util.Date parseDate(String line) throws ParseException {
        return logSDF.parse(line.substring(1, line.indexOf(">")));
    }
}
